package com.zzz.codegen;

import cn.hutool.core.util.StrUtil;
import cn.hutool.db.meta.MetaUtil;
import com.zzz.codegen.config.GlobalConfig;
import com.zzz.codegen.config.TemplateConfig;
import com.zzz.codegen.entity.GenResult;
import com.zzz.codegen.entity.TableVO;
import com.zzz.codegen.template.ITemplate;
import com.zzz.codegen.util.CodegenUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;

import javax.sql.DataSource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Fast 代码生成器。
 *
 * @author 重楼
 */
@Getter
@Setter
@Accessors(chain = true)
public class FastGenerator {

    protected DataSource dataSource;
    protected GlobalConfig globalConfig;

    public FastGenerator(DataSource dataSource, GlobalConfig globalConfig) {
        this.dataSource = dataSource;
        this.globalConfig = globalConfig;
    }

    public List<GenResult> generate() {
        List<String> tableNames = MetaUtil.getTables(dataSource);
        if (CollectionUtils.isEmpty(tableNames)) {
            System.out.println("table not found.");
            return null;
        }
        List<TableVO> tableVOList = tableNames.stream().map(t -> TableVO.cp(MetaUtil.getTableMeta(dataSource, t))).collect(Collectors.toList());
        return generateByTableVOList(globalConfig, tableVOList);
    }

    public static List<TableVO> buildTableVOListByTableNames(DataSource dataSource, List<String> tableNames) {
        if (CollectionUtils.isEmpty(tableNames)) {
            return null;
        }
        return tableNames.stream().map(t -> TableVO.cp(MetaUtil.getTableMeta(dataSource, t))).collect(Collectors.toList());
    }

    public static List<GenResult> generateByTableVOList(GlobalConfig globalConfig, List<TableVO> tableVOList) {
        List<GenResult> genResults = new ArrayList<>();
        for (TableVO table : tableVOList) {
            //表名称转Java类名称
            table.setEntityName(CodegenUtil.getEntityJavaFileName(globalConfig.getGroup(), table));
            //config 中冗余 table 和 group
            globalConfig.getConfigMap().forEach((k, config) -> {
                config.setTable(table);
                config.setGroup(globalConfig.getGroup());
            });

            Map<String, Object> params = new HashMap<>(2);
            params.put("table", table);
            params.put("configs", globalConfig.getConfigMap());
            //生成自定义文件
            globalConfig.getConfigMap().forEach((k, config) -> {
                GenResult genResult = generateSingleFile(config, globalConfig.getTemplate(), params);
                genResults.add(genResult);
            });
        }
        System.out.println("generated end.");
        return genResults;
    }

    /**
     * 生成单个文件
     *
     * @param templateConfig
     * @param template
     * @param params
     * @return
     */
    public static GenResult generateSingleFile(TemplateConfig templateConfig, ITemplate template, Map<String, Object> params) {
        TableVO table = templateConfig.getTable();
        GenResult genResult = new GenResult().setGenType(templateConfig.getGenType()).setTableName(table.getTableName());
        if (!templateConfig.isGenerateEnable()) {
            return genResult;
        }
        String genContent = null;
        if (StrUtil.isNotBlank(templateConfig.getTemplateContent())) {
            genContent = template.generateByContent(params, templateConfig.getTemplateContent());
        } else {
            genContent = template.generate(params, templateConfig.getTemplatePath());
        }
        genResult.setGenContent(genContent);
        if (templateConfig.isCreateFileEnable() && StrUtil.isNotBlank(genContent)) {
            File javaFile = templateConfig.getFileBuilder().apply(templateConfig);
            genResult.setFilePath(javaFile.getPath());
            //若文件已存在，重命名
            if (javaFile.exists() && !templateConfig.isOverwriteEnable()) {
                System.out.println("file exists ---> " + javaFile);
                return genResult;
            }
            try {
                FileUtils.write(javaFile, genContent, StandardCharsets.UTF_8);
                System.out.println("write file ---> " + javaFile);
            } catch (Exception e) {
                System.out.println(String.format("write file [%s] error：%s", javaFile.getPath(), e.getMessage()));
            }
        }

        return genResult;
    }
}
